/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.action;

import com.inspur.edp.bef.api.BefRtBeanUtil;
import com.inspur.edp.bef.api.be.IBEContext;
import com.inspur.edp.bef.api.be.IBEManagerContext;
import com.inspur.edp.bef.api.exceptions.BefDataPermissionDeniedException;
import com.inspur.edp.bef.api.exceptions.BefFuncPermissionDeniedException;
import com.inspur.edp.bef.api.lcp.AuthInfo;
import com.inspur.edp.bef.api.lcp.BefContext;
import com.inspur.edp.bef.core.DotNetToJavaStringHelper;
import com.inspur.edp.bef.core.action.authorityinfo.DataPermissionCtrlProvider;
import com.inspur.edp.bef.core.be.BEContext;
import com.inspur.edp.bef.core.be.BEManagerContext;
import com.inspur.edp.bef.core.be.CoreBEContext;
import com.inspur.edp.bef.core.session.BEFuncSessionBase;
import com.inspur.edp.bef.core.session.FuncSession;
import com.inspur.edp.bef.core.session.FuncSessionManager;
import com.inspur.edp.bef.spi.auth.DataPermissionCache;
import com.inspur.edp.bef.spi.auth.DataPermissionController;
import com.inspur.edp.cef.api.ValueGetterConfig;
import com.inspur.edp.cef.api.authority.AuthorityInfo;
import com.inspur.edp.cef.entity.changeset.ChangeType;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.spi.entity.IAuthFieldValue;
import com.inspur.edp.udt.entity.ISimpleUdtData;
import io.iec.edp.caf.permission.api.data.runtime.datapermission.DataPermissionContext;
import io.iec.edp.caf.permission.api.manager.runtime.DataPermissionManager;
import io.iec.edp.caf.permission.api.manager.runtime.PermissionManager;
import io.iec.edp.caf.runtime.config.CefBeanUtil;
import io.iec.edp.caf.securityentry.api.common.AuthType;
import io.iec.edp.caf.securityentry.api.data.AuthFieldEntry;
import io.iec.edp.caf.securityentry.api.data.PermissionEntity;
import io.iec.edp.caf.securityentry.api.data.SecurityEntry;
import io.iec.edp.caf.securityentry.api.manager.SecurityEntryService;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.StringUtils;

public class AuthorityUtil {

    private static SecurityEntryService securityEntryService;
    static SecurityEntryService getSecurityEntryService()
    {
        if(securityEntryService==null)
            securityEntryService= CefBeanUtil.getAppCtx().getBean(SecurityEntryService.class);
        return securityEntryService;
    }

    private static PermissionManager permissionManager;

    static PermissionManager getPermissionManager() {
        if(permissionManager==null)
            permissionManager=  CefBeanUtil.getAppCtx().getBean(PermissionManager.class);
        return permissionManager;
    }


    private static DataPermissionManager dataPermissionManager;

    static DataPermissionManager getDataPermissionManager() {
        if(dataPermissionManager==null)
            dataPermissionManager=  CefBeanUtil.getAppCtx().getBean(DataPermissionManager.class);
        return dataPermissionManager;
    }

    /**
     * 操作权限控制
     *
     * @param actionCode
     */
//    public static void checkOpAuthority(String actionCode, IBEManagerContext beManagerContext)
//    {
//        if(hasOpAuthByCache(actionCode,beManagerContext))
//            return;
//
//        SecurityEntry entry = createEntry(AuthType.Func);
//        //   CafContext.Current.CurrentSU = "sys";
//        String operationId = getSecurityEntryService().getFuncOperation(entry, actionCode);
//        if (DotNetToJavaStringHelper.isNullOrEmpty(operationId)) {
//            return;
//        }
//
//        Boolean permissionRez = CefBeanUtil.getAppCtx().getBean(PermissionManager.class).isPrincipalHasOp(operationId);
//        if (!permissionRez) {
//            throw new BefFuncPermissionDeniedException();
//        }
//        else
//        {addOpAuth(actionCode,beManagerContext);}
//    }

    @Deprecated
    public static void checkAuthority(String actionCode) {
        SecurityEntry entry = createEntry(AuthType.Func);
        String operationId = getSecurityEntryService().getFuncOperation(entry, actionCode);
        if (DotNetToJavaStringHelper.isNullOrEmpty(operationId)) {
            return;
        }

        Boolean permissionRez = CefBeanUtil.getAppCtx().getBean(PermissionManager.class).isPrincipalHasOp(operationId);
        if (!permissionRez) {
            throw new BefFuncPermissionDeniedException();
        }
    }
    @Deprecated
    public static void checkAuthority(String actionCode, FuncSession session) {
        SecurityEntry entry = createEntry(AuthType.Func, session);
        String operationId = getSecurityEntryService().getFuncOperation(entry, actionCode);
        if (DotNetToJavaStringHelper.isNullOrEmpty(operationId)) {
            return;
        }

        Boolean permissionRez = CefBeanUtil.getAppCtx().getBean(PermissionManager.class).isPrincipalHasOp(operationId);
        if (!permissionRez) {
            throw new BefFuncPermissionDeniedException();
        }
    }
//TODO:权限逻辑应统一挪到ErpStyleDataPermissionController
    public static  void checkAuthority(String actionCode, FuncSession session, BEManagerContext beManagerContext) {
        if(session.getBefContext().getAuthInfo().isEmpty()) {
            return;
        }
        SecurityEntry entry = createEntry(AuthType.Func, session);
        PermissionEntity permissionEntity = beManagerContext.getPermissionEntityByCache(entry,actionCode);

//        if(permissionEntity == null) {
//            // 缓存中没有获取到permissionEntity
//            permissionEntity = getPermissionEntityByRpc(entry,actionCode);
//            // 对permissionEntity进行缓存
//            beManagerContext.cacheSecurityEntryAndPermissionEntity(entry,actionCode,permissionEntity);
//        }

        if(permissionEntity != null && permissionEntity.isActionEnable() == false) {
            throw new BefFuncPermissionDeniedException();
        }
    }

//    private static  Boolean getPermissionResult(SecurityEntry entry, String actionCode) {
//        String operationId = getSecurityEntryService().getFuncOperation(entry, actionCode);
//        if (DotNetToJavaStringHelper.isNullOrEmpty(operationId)) {
//            return null;
//        }
//        return CefBeanUtil.getAppCtx().getBean(PermissionManager.class).isPrincipalHasOp(operationId);
//    }

//    private static boolean hasOpAuthByCache(String actionCode,IBEManagerContext managerContext) {
//
//    }

    /**数据权限控制*/
    public static void checkDataAuthority(IBEContext beContext) {
        checkDataAuthority(((BEContext) beContext).getSessionItem().getFuncSession().getBefContext()
            .getCurrentOperationType(), beContext);
    }

    @Deprecated
    public static void checkDataAuthority(String actionCode, IBEContext beContext) {
      if (beContext.getCurrentData() == null) {
          return;
      }
      IChangeDetail currentChange = beContext.getCurrentChange();
      if(currentChange !=null&& currentChange.getChangeType()== ChangeType.Added)
          return;
      if(beContext.getOriginalData()==null)
          return;

      BEFuncSessionBase sessionItem = ((BEContext)beContext).getSessionItem();
      if(beContext.getBizEntity() == null
              || beContext.getBizEntity().getBEType() == null
              ||! beContext.getBizEntity().getBEType()
              .equals(sessionItem.getFuncSession().getBefContext().getAuthInfo().getSourceType()))
          return;
      // string requestSU = CafContext.Current.CurrentSU;
      //try
      // {
//      SecurityEntryService service = CefBeanUtil.getAppCtx().getBean(SecurityEntryService.class);

//      SecurityEntry entry = createEntry(AuthType.Auth);
//      List<AuthFieldEntry> fields = getSecurityEntryService().getAuthFieldEntry(entry, actionCode);
        if(sessionItem.getFuncSession().getBefContext().getAuthInfo().isEmpty()) {
            return;
        }
        tryBuildDataPermissionController(sessionItem);
        if (!sessionItem.getDataPermissionCtrl()
            .checkDataAuthority(actionCode, beContext, sessionItem.getFuncSession().getBefContext().getAuthInfo(), sessionItem.getDataPermissionCache())) {
            throw new BefDataPermissionDeniedException();
        }
        List<AuthFieldEntry> fields =  getAuthFieldEntryList(actionCode, (BEManagerContext)(((CoreBEContext)beContext).getBEManagerContext()));
      if (fields == null || fields.isEmpty()) {
          return;
      }
      ArrayList<DataPermissionContext> permissions = new ArrayList<DataPermissionContext>();

      List<String> values =new ArrayList<>();

      for (AuthFieldEntry field : fields) {
          String data = null;
          ValueGetterConfig valueGetterConfig=new ValueGetterConfig();
          valueGetterConfig.setAssociationValue(false);
          valueGetterConfig.setSingleValueUdt(true);
          Object tempVar= BefRtBeanUtil.getValueGetter().getValue(beContext.getCurrentData(),field.getFieldId(),valueGetterConfig);
          IAuthFieldValue authFieldValue = (IAuthFieldValue) ((tempVar instanceof IAuthFieldValue) ? tempVar : null);
          if(tempVar!=null&&tempVar instanceof ISimpleUdtData)
          {
              ISimpleUdtData data1= (ISimpleUdtData ) tempVar;
              if(data1.getValue()!=null&&data1.getValue() instanceof  IAuthFieldValue)
              {
                  data=((IAuthFieldValue)data1.getValue()).getValue();
              }
              else if(data1.getValue()==null)
                  data=null;
              else
                  data =  String.valueOf(data1.getValue());
          }
          else if (authFieldValue == null) {
              data = String.valueOf(beContext.getCurrentData().getValue(field.getFieldId()));
          }
          else
              {
              data = authFieldValue.getValue();
          }
          if(data==null||data.equals(""))
              continue;
          values.add(data);
          DataPermissionContext context = new DataPermissionContext();
          context.setData(data);
          context.setAuthFieldId(field.getAuthFieldId());
          context.setAuthorizationId(field.getAuthObjId());
          context.setAuthOp(field.getAuthOpRelations().get(0).getOperationId());

          permissions.add(context);
      }
      if(permissions==null||permissions.size()==0)
          return;
      String[] array = new String[values.size()];
      values.toArray(array);
      if(hasDataAuthByCache(beContext,actionCode,array))
          return;

      Boolean permissionRez = getDataPermissionManager().isHasDataPermission(permissions);
      if(permissionRez==true)
          addDataAuthToCache(beContext,actionCode,array);
      if (!permissionRez) {
          throw new BefDataPermissionDeniedException();
      }
//	    }
//		catch
//		{
//		    throw new RuntimeException("");
//		}
//		finally
//		{
//		    CafContext.Current.CurrentSU = requestSU;
//		}
    }

    private static void tryBuildDataPermissionController(BEFuncSessionBase sessionItem) {
        if (sessionItem.getDataPermissionCtrl() != null) {
            return;
        }
        AuthInfo authInfo = sessionItem.getFuncSession().getBefContext().getAuthInfo();
        DataPermissionController controller =
            StringUtils.isEmpty(authInfo.getAuthType())
                ? DataPermissionCtrlProvider.getInstance().getDefaultController()
                : DataPermissionCtrlProvider.getInstance()
                    .getController(authInfo.getAuthType(), true);
        DataPermissionCache cache = controller.buildCache();
        sessionItem.setDataPermissionCtrl(controller);
        sessionItem.setDataPermissionCache(cache);
    }

    private static List<AuthFieldEntry> getAuthFieldEntryList(String actionCode, BEManagerContext beManagerContext) {
        SecurityEntry authSecurityEntry = beManagerContext.getSecurityEntry(createEntry(AuthType.Auth));
        if(authSecurityEntry == null) {
            return null;
        }
        return authSecurityEntry.getAuthFieldEntryListByAction(actionCode);
    }

    private static void addDataAuthToCache(IBEContext beContext, String actionCode,
        String[] array) {
        if(beContext instanceof CoreBEContext)
        {((CoreBEContext) beContext).addAuthorityInfos(actionCode,array);}
    }

    private static boolean hasDataAuthByCache(IBEContext beContext,String actionCode, String[] values) {
        if(beContext instanceof CoreBEContext) {
            return  ((CoreBEContext) beContext)
                .hasValues(actionCode, values);
        }
        return false;
    }

    public static SecurityEntry createEntry(AuthType authType, FuncSession session) {
        BefContext befContext = session.getBefContext();
        SecurityEntry entry = new SecurityEntry();
        entry.setEx1(befContext.getAuthInfo().getExtend1());
        entry.setEx2(befContext.getAuthInfo().getExtend2());
        entry.setEx3(befContext.getAuthInfo().getExtend3());
        entry.setEx4(befContext.getAuthInfo().getExtend4());
        entry.setEx5(befContext.getAuthInfo().getExtend5());
        entry.setExtType(befContext.getAuthInfo().getExtType());
        entry.setAuthType(authType);
        return entry;
    }

    @Deprecated
    public static SecurityEntry createEntry(AuthType authType) {
        FuncSession session = FuncSessionManager.getCurrentSession();
        // 存befContext
        BefContext befContext = session.getBefContext();
        SecurityEntry entry = new SecurityEntry();
        entry.setEx1(befContext.getAuthInfo().getExtend1());
        entry.setEx2(befContext.getAuthInfo().getExtend2());
        entry.setEx3(befContext.getAuthInfo().getExtend3());
        entry.setEx4(befContext.getAuthInfo().getExtend4());
        entry.setEx5(befContext.getAuthInfo().getExtend5());
        entry.setExtType(befContext.getAuthInfo().getExtType());
        entry.setAuthType(authType);
        return entry;
    }

    public static Boolean hasAuthority(IBEManagerContext mgrContext) {
        return mgrContext.getBEManager() != null
                && mgrContext.getBEManager().getBEType() != null
                && mgrContext.getBEManager().getBEType()
                .equals(((BEManagerContext)mgrContext).getSession().getBefContext().getAuthInfo().getSourceType())
            && !((BEManagerContext)mgrContext).getSession().getBefContext().getAuthInfo().isEmpty();
    }


    public static List<AuthorityInfo> getAuthorityInfos(BEFuncSessionBase sessionItem) {
        tryBuildDataPermissionController(sessionItem);
        return sessionItem.getDataPermissionCtrl().getQueryAuthInfo(
            sessionItem.getFuncSession().getBefContext().getAuthInfo(),
            sessionItem.getDataPermissionCache());
    }
}
